/*
 *  Copyright (c) 2012 - 2013 Gilles Dupeyrou
 * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
 */
var version = "0.46";

// Generic DOM element creation
function createElement(p, type, className) {
	var e = document.createElement(type);
	if (p)
		p.appendChild(e);
	if (className != undefined)
		e.className = className;
	return e;
}

wme_addons = Class.extend({
	init: function() {
		this.tb = $("#edit-buttons");
		this.buttons = [];

		this.logger = $('<div id="logger">')
			.css('width', '500')
			.css('background-color', 'rgba(0, 0, 0, 0.6)')
			.css('color', 'white')
			.css('font-size', '15px')
			.css('font-weight', 'bold')
			.css('margin-left', 'auto')
			.css('margin-right', 'auto')
			.appendTo($('#toolbar'));
	},
	log: function(msg, delay) {
		this.logger.append($('<div id="mylog">')
			.append(new Date().toLocaleDateString() + " " + new Date().toLocaleTimeString() + " : " + msg));//.show().delay(5000).fadeOut(100);
		setTimeout(function() {
			$('#logger').children().first().remove();
		}, delay ? delay : 5000);
	},
	add_menu_bt: function(id, icon) {
		var myMenuBt = $('<div id=' + id + '>')
			.addClass("toolbar-button toolbar-submenu")
			.addClass("toolbar-group-drawing")
			.addClass("ItemInactive");
		if (typeof(icon) === "undefined") {
			icon = document["WME_Icon"].src;
		}
		myMenuBt.attr('style', 'width:60px;background:url(' + icon + ') no-repeat center, -moz-linear-gradient(top , #FFFFFF 0%, #FFFFFF 5%, #A7CFDC 100%);background:url(' + icon + ') no-repeat center, -webkit-gradient(linear, left top, left bottom, color-stop(0%,#FFFFFF), color-stop(5%,#FFFFFF), color-stop(100%,#A7CFDC))');
		myMenuBt.hover(function() {
			$(this)
				.attr('style', 'width:60px;background: url(' + icon + ') no-repeat center, -moz-linear-gradient(top, #FFFFFF 0%, #FFFFFF 5%, #8EBCCC 100%);background: url(' + icon + ') no-repeat center,-webkit-gradient(linear, left top, left bottom, color-stop(0%,#FFFFFF), color-stop(5%,#FFFFFF), color-stop(100%,#8EBCCC))');
		},
			function() {
				$(this)
					.attr('style', 'width:60px;background:url(' + icon + ') no-repeat center, -moz-linear-gradient(top , #FFFFFF 0%, #FFFFFF 5%, #A7CFDC 100%);background:url(' + icon + ') no-repeat center, -webkit-gradient(linear, left top, left bottom, color-stop(0%,#FFFFFF), color-stop(5%,#FFFFFF), color-stop(100%,#A7CFDC))');
			}
		);
		this.tb.width = parseInt(this.tb.css("width")) + 2 + (parseInt(this.tb.css("width")) / $(".toolbar-button", this.tb).length);
		this.tb.css("width", this.tb.width + "px");
		myMenuBt.menu = $('<menu class="submenu">');
		myMenuBt.append(myMenuBt.menu);
		this.tb.append(myMenuBt);
		this.buttons[id] = myMenuBt;
		return myMenuBt;
	},
	add_menu_entry: function(menu, title, callback, tooltip) {
		ret = $("<div>").addClass("drawing-toolbar-button ItemInactive")
			.appendTo(menu).attr("title", tooltip).append("<span>" + title + "</span>")
			.click(function(e)
		{
			if (callback && typeof(callback) === "function") {
				callback();
			}
		});
		return ret;
	},
	add_submenu_entry: function(menu, title, tooltip) {
		ret = $("<div>").addClass("drawing-toolbar-button ItemInactive")
			.attr("title", tooltip).attr("style", "height:32px")
			.append("<span>" + title + "</span>")
			.hover(function() {
			$(this).children("div:first").show();
		},
			function() {
				$(this).children("div:first").hide();
			})
			.appendTo(menu);
		$("<div id='submen'>")
			.addClass("drawing-toolbar-button ItemInactive")
			.attr("style", "position: relative; bottom: " + ret.height()
			.toString() + "px !important; left: " + ret.width()
			.toString() + "px !important")
			.hide()
			.appendTo(ret);

		return ret;
	},
	add_submenu_item: function(submenu, title, callback, args, tooltip) {
		submenu.children("div:first").append($("<div>")
			.addClass("drawing-toolbar-button ItemInactive")
			.attr("title", tooltip)
			.append("<span>" + title + "</span>")
			.click(function(e)
		{
			if (callback && typeof(callback) === "function") {
				callback(args);
			}
		}));
	}
});

var defOptions = {
	customLinks: {OSM: "http://www.openstreetmap.org/?lat=%lat%&lon=%lon%&zoom=(12+%zoom%)&layers=M"},
	alpha: 75,
	snapdst: 15,
	columns: ['Country', 'State', 'City', 'Street']
};

var toSave = {};
var o = localStorage.WMEAddons || '{}';
console.log("localStorage.WMEAddons: " + o);
o = JSON.parse(o);
for (var k in defOptions)
	toSave[k] = (typeof o[k] != 'undefined') ? o[k] : defOptions[k];
localStorage.WMEAddons = JSON.stringify(toSave);

$(window).bind('beforeunload', function(eventObject) {
	var returnValue = undefined;
	eventObject.returnValue = returnValue;
	localStorage.WMEAddons = JSON.stringify(toSave);
	console.log("localStorage.WMEAddons: " + localStorage.WMEAddons);
	return returnValue;
});

var PossibleColumns = [
	'Country', 'State', 'City', 'StreetName', 'Street', 'StreetAlt', 'StreetId',
	'Length', 'LockRank', 'Toll', 'Separator', 'level', 'roadTypeStr', 'CreatedBy', 'UpdatedBy', 'InLndMark', 'InScreen',
	'NbWays', 'RoundAbout', 'AllowNoDirection', 'FwdSpeed', 'RevSpeed'];

var RoadTypeString = {
	1: "Streets",
	2: "Primary Street",
	3: "Freeways",
	4: "Ramps",
	5: "Walking Trails",
	6: "Major Highway",
	7: "Minor Highway",
	8: "Dirt roads",
	10: "Pedestrian Bw",
	16: "Stairway",
	17: "Private Road",
	18: "Railroad",
	19: "Runway/Taxiway",
	20: "Parking Lot Road",
	21: "Service Road"
};

var RoadTypePriority = {
	0: 0,
	1: 1,
	2: 2,
	3: 3,
	4: 0,
	5: 0,
	6: 5,
	7: 4,
	8: .5,
	10: 0,
	16: 0,
	17: .7,
	18: 0,
	19: 0,
	20: .8,
	21: .6
};

function getSelectedLandMark() {
	var lmList = [];
	for (var i = 0; i < Waze.selectionManager.selectedItems.length; i++) {
		var m = Waze.selectionManager.selectedItems[i];
		if (m.type == Waze.Model.ObjectType.LANDMARK)
			lmList.push(m.geometry);
	}

	if (lmList.length == 0) {
		for (var id in Waze.model.landmarks.objects) {
			if (id < 0) {
				var curLm = Waze.model.landmarks.objects[id];
				var curFid;
				if (lmList.length == 0 || id < curFid) {
					lmList[0] = curLm.geometry;
					curFid = id;
				}
			}
		}
	}
	return lmList;
}

function getAddress(seg) {
	try {
		var f = seg.model.streets.get(seg.attributes.primaryStreetID), e, c, d, a, b = seg;
		if (f) {
			e = seg.model.cities.get(f.cityID);
			c = seg.model.states.get(e.stateID);
			d = seg.model.countries.get(e.countryID);
			a = seg.attributes.streetIDs.map(function(g) {
				b.model.streets.get(g);
			});
		}
		return {street: f, city: e, state: c, country: d, altStreets: a};
	} catch (err) {
		addons.log("Error on getting attributes :" + err.message);
		return {street: "Error", city: "Error", state: "Error", country: "Error", altStreets: "Error"};
	}
}

function getStreetNameElt(streetName) {
	if (!streetName) {
		return ['', ''];
	}
	;
//  if (streetName.match(/^[ADRN]\d+\w?\b(?! ?:)/)){
	if (streetName.match(/^[ACDMN]\d{1,5}(?:(?:\w?\d?)|(?:[IXVLCDM]*))\b(?! ?:)/)) {
//    r = [streetName.match(/^[ADRN]\d+\w?\b(?! ?:)/)[0],streetName.split(/-[!\s.]+/)[1]||''];
		r = [streetName.match(/^[ACDMN]\d{1,5}(?:(?:\w?\d?)|(?:[IXVLCDM]*))\b(?! ?:)/)[0], streetName.split(/-[!\s.]+/)[1] || ''];
	} else {
		r = ['', streetName];
	}
	return r;
}

function getAttr(attr, seg) {
	var x = '';
	var attrs = seg.getAddress();
	switch (attr) {
		case 'Country':
			x = (Waze.Util.defined(attrs.country) && Waze.Util.defined(attrs.country.name)) ? attrs.country.name : "";
			break;
		case 'countryID':
			x = attrs.country ? attrs.country.id : "";
			break;
		case 'State':
			x = (Waze.Util.defined(attrs.state) && Waze.Util.defined(attrs.state.name)) ? attrs.state.name : "";
			break;
		case 'stateID':
			x = attrs.state ? attrs.state.id : "";
			break;
		case 'City':
			x = (Waze.Util.defined(attrs.city) && Waze.Util.defined(attrs.city.name)) ? attrs.city.name : "";
			break;
		case 'cityID':
			x = attrs.city ? attrs.city.id : "";
			break;
		case 'Street':
			x = (Waze.Util.defined(attrs.street) && Waze.Util.defined(attrs.street.name)) ? attrs.street.name : "";
			break;
		case 'StreetName':
			st = getStreetNameElt(attrs.street ? attrs.street.name : "");
			x = st[1];
			break;
		case 'StreetAlt':
			x = "Todo";
			break;
		case 'StreetId':
			st = getStreetNameElt((Waze.Util.defined(attrs.street) && Waze.Util.defined(attrs.street.name)) ? attrs.street.name : "");
			x = st[0];
			break;
		case 'primaryStreetID':
			x = seg.attributes["primaryStreetID"] ? seg.attributes["primaryStreetID"] : "Unknow";
			break;
		case 'Length':
			x = seg.attributes["length"] ? seg.attributes["length"] : "Unknow";
			break;
		case 'LockRank':
			x = seg.attributes["lockRank"] ? seg.attributes["lockRank"] : 0;
			break;
		case 'Toll':
			x = (seg.attributes.fwdToll + seg.attributes.revToll) / 2;
			break;
		case 'Separator':
			x = seg.attributes["separator"] ? seg.attributes["separator"] : "False";
			break;
		case 'level':
			x = seg.attributes["level"] ? seg.attributes["level"] : "Unknow";
			break;
		case 'roadTypeStr':
			x = RoadTypeString[seg.attributes.roadType];
			break;
		case 'roadType':
			x = seg.attributes.roadType;
			break;
		case 'CreatedBy':
			x = "";
			var cb = seg.attributes.createdBy;
			if (cb > 0) {
				cb = Waze.model.users.objects[cb];
				if (cb != null)
					x = cb.userName + ' (' + cb.normalizedLevel + ')';
			}
			break;
		case 'UpdatedBy':
			x = "";
			var cb = seg.attributes.updatedBy;
			if (cb > 0) {
				cb = Waze.model.users.objects[cb];
				if (cb != null)
					x = cb.userName + ' (' + cb.normalizedLevel + ')';
			}
			break;
		case 'InLndMark':
			x = isInLanmarks(seg);
			break;
		case 'InScreen':
			var g = [Waze.map.getExtent().toGeometry()];
			if (isSegmentInGeometries(g, seg, false))
				return 1;
			if (!isSegmentInGeometries(g, seg, true))
				return 0;
			x = 0.5;
			break;
		case 'NbWays':
			x = (seg.attributes.fwdDirection ? 1 : 0) + (seg.attributes.revDirection ? 1 : 0);
			break;
		case 'RoundAbout':
			x = seg.attributes.junctionID != null;
			break;
		case 'AllowNoDirection':
			x = seg.attributes.allowNoDirection;
			break;
		case 'FwdSpeed':
			x = seg.attributes["fwdCrossSpeed"] ? seg.attributes["fwdCrossSpeed"] : 0;
			break;
		case 'RevSpeed':
			x = seg.attributes["revCrossSpeed"] ? seg.attributes["revCrossSpeed"] : 0;
			break;
	}
	return x;
}

function mapModel(columns, segArray) {
	var map = new Object();
	for (var i = 0; i < segArray.length; i++) {
		if (segArray[i].type == Waze.Model.ObjectType.SEGMENT) {
			var maplvl = map;
			var seg = segArray[i];
			for (var j = 0, len = columns.length; j < len; j++) {
				var key = getAttr(columns[j], seg);
				var m = maplvl[key];
				if (m == null) {
					m = {};
					maplvl[key] = m;
				}
				maplvl = m;
			}
			var lSt = maplvl[null];
			if (lSt == null) {
				lSt = new Array();
				maplvl[null] = lSt;
			}
			lSt.push(seg);
		} else {
			addons.log("Warning : not a segment :" + id.toString());
		}
	}

	return map;
}

function fillTable(theTable, themap, cols) {
	if (themap instanceof Array) {
		if (themap.length > 0) {
			var seg = themap[0];
			trs = $('<tr border="1px solid #eee" padding=".6em 10px" text-align="left">');
			for (var j = 0; j < cols.length; j++) {
				var col = cols[j];
				trs.append('<td>' + getAttr(col, seg) + '</td>');
			}
			trs.append($('<td>')
				.append('<button style="width:50px">' + themap.length.toString() + '</button>')
				.click(function() {
				Waze.selectionManager.select(themap);
			}));
			trs.append('</td></tr>');
			theTable.append(trs);
		}
	} else {
		for (var colIdx in themap) {
			fillTable(theTable, themap[colIdx], cols);
		}
	}
}

function clearlist(segArray) {
	dlg.refresh(segArray);
}

function segmentList() {
	if (typeof(dlg) === 'undefined') {
		dlg = new lstdialog();
		dlg.opts.accordion({active: false});
	}
	dlg.refresh($.map(Waze.model.segments.objects, function(e, f) {
		return e;
	}));
	dlg.popup.dialog("open");
}

lstdialog = Class.extend({
	init: function() {
		this.popup = $(createElement(document.body, 'DIV', 'dialog-form'))
			.css('font-size', '70.5%');
		this.opts = $('<div style="max-height:150px;overflow:auto;"><h5>Columns</h5>')
			.accordion({
//	    icons : {header :'ui-icon-gear',activeHeader:'ui-icon-gear'},
			collapsible: true
//	    active:false,
		}).attr('title', 'Select columns to display');
		var container = $('<div id="contain" style="display:table">');
		var col = [];
		col[0] = $('<div style="display:table-cell;width:20%">');
		col[1] = $('<div style="display:table-cell;width:20%">');
		col[2] = $('<div style="display:table-cell;width:20%">');
		col[3] = $('<div style="display:table-cell;width:20%">');
		col[4] = $('<div style="display:table-cell;width:20%">');
		for (var i = 0; i < PossibleColumns.length; ) {
			for (var j = 0; j < col.length; j += 1) {
				if (i < PossibleColumns.length) {
					var chk = $('<input type="checkbox" name="options[]" value="' + PossibleColumns[i] + '"/>')
						.attr('checked', $.inArray(PossibleColumns[i], toSave.columns) >= 0);
					col[j].append($('<label style="font-size: 1em;margin-bottom: 5px;line-height: 3px;"/>')
						.append(chk).append(PossibleColumns[i]));
				}
				i += 1;
			}
		}
		container.append(col);
		this.opts.append(container);
		this.slist = $('<div>');
		this.columns = toSave.columns;
		this.popup.append(this.tb);
		this.popup.append(this.opts);
		this.popup.append(this.slist);
		this.popup.dialog({
			title: "Segment list",
			autoOpen: false,
			height: 350,
			dialogClass: "seglist",
			width: 430,
			modal: false,
			buttons: {
				Cancel: function() {
					$(this).dialog("close");
				}
			},
			close: function() {
				toSave.columns.length = 0;
				$("input[name='options[]']:checked").each(function(i) {
					toSave.columns.push(this.value);
				});
			}
		});
		$('div.seglist')
			.attr('style', 'position: absolute; top: 0; left: 0; padding: .2em; width: 300px; overflow: hidden;background:rgba(255, 255, 255, ' + toSave.alpha / 100 + ')');
		$('div.ui-dialog-titlebar', $('div.seglist'))
			.attr('style', 'height:10px;font-size:8px;line-height: 10px')
			.append($('<span height="10px">')
			.button({icons: {primary: 'ui-icon-refresh'}})
			.attr('title', 'Refresh whole segment list in the map')
			.click(function(e) {
			clearlist($.map(Waze.model.segments.objects, function(e, f) {
				return e;
			}));
		}))
			.append($('<span height="10px">')
			.button({icons: {primary: 'ui-icon-calculator'}})
			.attr('title', 'Refresh selected segment list')
			.click(function(e) {
			clearlist(Waze.selectionManager.selectedItems);
		}));
		$('div.ui-dialog-buttonpane')
			.attr('style', 'height:25px;font-size:8px;line-height: 10px').last()
			.append($('<div>').slider({
			value: toSave.alpha,
			change: function(event, ui) {
				$('div.seglist')
					.css('background', 'rgba(255, 255, 255,' + ui.value / 100 + ')');
				toSave.alpha = ui.value;
			}
		}).attr('style', 'float:left;margin-top: 10px;width:50%')
			.attr('title', 'Adjust background transparency'));
	},
	add_ToolBt: function(label, callback) {
		this.tb.append($('<div>').append(label).button().click(function(e) {
			if (callback && typeof(callback) === "function") {
				callback();
			}
		}));
	},
	refresh: function(segArray) {
		this.columns.length = 0;
		var cols = this.columns;
		$.each($("input[name='options[]']:checked"), function() {
			cols.push(this.value);
		});
		this.slist.empty();
		if (Waze.map.getZoom() <= 1) {
			addons.log('Unapropriate Zoom level :' + Waze.map.getZoom().toString());
			return;
		}
		if (pendingControl.pending.length > 0) {
			addons.log("WazeMap is refreshing, please wait");
			return;
		}
		var myTable = $('<table id="seg-list" border="1px solid #eee" margin="1em 0" padding="6em 10px" border-collapse="collapse" width="100%" text-align="left">');
		myHead = $('<thead>');
		myRow = $('<tr class="ui-widget-header" border="1px solid #eee" padding=".6em 10px" text-align="left">');
		$.each(cols, function(index, value) {
			myRow.append('<td>' + value);
		});
		myRow.append('<td width="50px">Select');
		myHead.append(myRow);
		myBody = $('<tbody>');
		var mymap = mapModel(cols, segArray);
		fillTable(myBody, mymap, cols);
		myTable.append(myHead);
		myTable.append(myBody);
		this.slist.append(myTable);
		if (myTable.children()[1].childElementCount == 0) {
			myTable.append('<tr style="color:red; font-weight: bold; text-align:center !important"><td colspan=7 >The list is empty, try to zoom deeper or refresh the page...</td></tr>');
		}
		window.ts_makeSortable(myTable[0]);
	}
});

function CSelectLandMark(strictInclude) {
	var geoList = [];

	for (var i = 0; i < Waze.selectionManager.selectedItems.length; i++) {
		var m = Waze.selectionManager.selectedItems[i];
		if (m.type == Waze.Model.ObjectType.LANDMARK)
			geoList.push(m.geometry);
	}

	if (geoList.length == 0) {
		for (var id in Waze.model.landmarks.objects) {
			if (id < 0) {
				var curLm = Waze.model.landmarks.objects[id];
				var curFid;
				if (geoList.length == 0 || id < curFid) {
					geoList[0] = curLm.geometry;
					curFid = id;
				}
			}
		}
	}

	if (geoList.length > 0) {
		var lSeg = new Array();
		for (var id in Waze.model.segments.objects) {
			var seg = Waze.model.segments.objects[id];
			if (isSegmentInGeometries(geoList, seg, !strictInclude))
				lSeg.push(seg);
		}

		Waze.selectionManager.select(lSeg);
	}
	else {
		addons.log("No new or selected landmark found");
	}
}

function isSegmentInGeometries(geoList, seg, partialAllowed) {
	for (var i = 0; i < seg.geometry.components.length; i++) {
		var p = seg.geometry.components[i];
		var found = false;
		for (var j = 0; j < geoList.length; j++) {
			var geo = geoList[j];
			if (geo.containsPoint(p)) {
				if (partialAllowed)
					return true;
				found = true;
				break;
			}
		}
		if (!partialAllowed && !found)
			return false;
	}
	return !partialAllowed;
}

function isInLanmarks(seg) {
	var val = null;
	for (var i = 0; i < seg.geometry.components.length; i++) {
		var p = seg.geometry.components[i];
		var v = 0;
		var lnmLst = getSelectedLandMark();
		for (var j = 0; j < lnmLst.length; j++) {
			if (lnmLst[j].containsPoint(p)) {
				v = 1;
				break;
			}
		}
		if (val == null)
			val = v;
		else if (val != v)
			return .5;
	}
	return val;
}

function CSuppressUnneededJunctions() {
	if (pendingControl.pending.length > 0) {
		addons.log("WazeMap is refreshing, please wait");
		return;
	}
	var g = Waze.map.getExtent().toGeometry();
	var z = Waze.map.getZoom();
	if (z < 4) {
		addons.log("current zoom : " + z.toString());
		addons.log("You must increase your zoom level to perform this action");
		return;
	}

	var action = new Waze.Action.MultiAction();
	Waze.model.actionManager.add(action);
	for (var nodeID in Waze.model.nodes.objects) {
		var node = Waze.model.nodes.objects[nodeID];
		var ok = true;
		if (ok && node.state == "Delete")
			ok = false;
		if (ok && node.attributes.segIDs.length != 2)
			ok = false;
		if (ok && !node.isAllowed(node.PERMISSIONS.DELETE))
			ok = false;
		if (ok && !g.containsPoint(node.geometry))
			ok = false;
		if (ok) {
			var segs = node.attributes.segIDs.map(function(s) {
				return Waze.model.segments.objects[s];
			});
			var attr0 = segs[0].attributes;
			var attr1 = segs[1].attributes;
			if (ok && attr0.junctionID != null)
				ok = false;
			if (ok && attr1.junctionID != null)
				ok = false;
			if (ok && attr0.primaryStreetID != attr1.primaryStreetID)
				ok = false;
			if (ok && attr0.roadType != attr1.roadType)
				ok = false;
			if (ok && attr0.locked != attr1.locked)
				ok = false;
			if (ok) {
				var nodeID2 = attr0.fromNodeID == nodeID ? attr0.toNodeID : attr0.fromNodeID;
				if (nodeID2 != null)
					if (attr1.fromNodeID == nodeID2 || attr1.toNodeID == nodeID2)
						ok = false;
			}

			if (ok) {
//         segs.forEach(function(seg) {
//           var attr = seg.attributes;
//           if(!attr.locked && !attr.fwdDirection && !attr.revDirection)
//             setAttrs({ direction: 3 },new Array(seg));
//         });
				action.doSubAction(new Waze.Action.ModifyAllConnections(node, true));
				action.doSubAction(new Waze.Action.MergeSegments(null, node));
			}
		}
	}
}

function cleanRDBT() {
	if ((Waze.selectionManager.selectedItems.length != 1) || (Waze.selectionManager.selectedItems[0].attributes.junctionID === null)) {
		addons.log("You must select one segment which is part of a roundabout");
		return;
	}
	var seg = Waze.selectionManager.selectedItems[0];
	var jId = seg.attributes.junctionID;
	var junc = Waze.model.junctions.objects[jId];
	if (junc === null) {
		addons.log("Error detected when analysing this junction, try to refresh the page or rebuild this roundabout");
		return;
	}
	var lst = new Array();
	var lst2 = new Array();
	var attrs = {"countryID": null, "stateID": null, "cityID": null, "City": null, "roadType": 0, "level": 0};
	rdsegs = junc.segIDs;
	junc.segIDs.forEach(function(segID, idx) {
		if (!Waze.model.segments.objects[segID]) {
			addons.log("Unknow error parsing segments of the roundabout, rebuild it or retry with deeper zoom level!");
			return;
		} else {
			lst.push(Waze.model.segments.objects[segID]);
			Waze.model.nodes.objects[Waze.model.segments.objects[segID].attributes.fromNodeID].attributes.segIDs.forEach(function(segID, idx) {
				if ($.inArray(segID, rdsegs) < 0) {
					lst2.push(Waze.model.segments.objects[segID]);
					if (Waze.model.segments.objects[segID].attributes['level'] > attrs['level']) {
						attrs['level'] = Waze.model.segments.objects[segID].attributes['level'];
					}
					if (RoadTypePriority[Waze.model.segments.objects[segID].attributes['roadType']] > RoadTypePriority[attrs['roadType']]) {
						attrs['roadType'] = Waze.model.segments.objects[segID].attributes['roadType'];
					}
					if (attrs['countryID'] === null) {
						attrs['countryID'] = getAttr("countryID", Waze.model.segments.objects[segID]);
					}
					if (attrs['stateID'] === null) {
						attrs['stateID'] = getAttr("stateID", Waze.model.segments.objects[segID]);
					}
					if (attrs['cityID'] === null) {
						attrs['cityID'] = getAttr("cityID", Waze.model.segments.objects[segID]);
					}
					if (attrs['City'] === null) {
						attrs['City'] = getAttr("City", Waze.model.segments.objects[segID]);
					}
				}
			});
		}
	});
	attrs["level"]++;
	attrs["locked"] = false;
	setAttrs(attrs, lst);
}

function setStreet(streetArray) {
	if ((streetArray[0] != "") && (streetArray[1] != "")) {
		return streetArray.join(" - ");
	} else if (streetArray[0] != "") {
		return streetArray[0];
	} else if (streetArray[1] != "") {
		return streetArray[1];
	} else
		return "";
}

function setAddress(attrs, newAttrs, seg) {
	var cntid, stID;
	if (attrs['countryID']) {
		cntid = attrs['countryID'];
	} else if (attrs['cityID']) {
		cntid = Waze.model.cities.get(attrs['cityID']).countryID;
	} else if ((attrs['City']) && (Waze.model.cities.getByAttributes({name: attrs['City']}).length > 0)) {
		cntid = Waze.model.cities.getByAttributes({name: attrs['City']})[0].countryID;
	} else if (getAttr('countryID', seg)) {
		cntid = getAttr('countryID', seg);
	} else { //last, get from topCityID attribute of segment list in the map
		cntid = Waze.model.cities.get(Waze.model.segments.topCityID).countryID;
	}
	if (attrs['stateID']) {
		stID = attrs['stateID'];
	} else if (attrs['cityID']) {
		stID = Waze.model.cities.get(attrs['cityID']).stateID;
	} else if ((attrs['City']) && (Waze.model.cities.getByAttributes({name: attrs['City']}).length > 0)) {
		stID = Waze.model.cities.getByAttributes({name: attrs['City']})[0].stateID;
	} else if (getAttr('stateID', seg)) {
		stID = getAttr('stateID', seg);
	} else {
		stID = Waze.model.cities.get(Waze.model.segments.topCityID).stateID;
	}
	var ctname = attrs['City'] ? attrs['City'] : getAttr('City', seg);
	var emptyct = (ctname === "");
	var fattr = {countryID: cntid, stateID: stID, isEmpty: emptyct};
	if (!emptyct) {
		fattr.name = ctname;
	}
	var ct = Waze.model.cities.getByAttributes(fattr);
	if (ct.length === 1) {
		newAttrs['cityID'] = ct[0].getID();
	} else if (ct.length === 0) {
		var f = new Waze.Action.CreateObject(Waze.Model.ObjectType.CITY, {
			countryID: cntid,
			stateID: stID,
			isEmpty: emptyct,
			name: ctname
		});
		Waze.model.actionManager.add(f);
		newAttrs['cityID'] = f.newObject.getID();
		addons.log('Created new ' + (emptyct ? 'empty ' : '') + 'city object ' + attrs['City']);
	} else {
		addons.log('Abort : Multiple cities with same name on same country! please check');
		return false;
	}
	var st = getStreetNameElt(getAttr('Street', seg));
	if (attrs['StreetId']) {
		st[0] = attrs['StreetId'];
	}
	if (attrs['StreetName']) {
		st[1] = attrs['StreetName'];
	}
	if ((attrs['StreetId']) || (attrs['StreetName'])) {
		newAttrs['Street'] = setStreet(st);
	}

	return true;
}

function getOrCreateCity(attrs, seg) {
}

function getOrCreateStreet(newAttrs, seg) {
	var stname = newAttrs['Street'] ? newAttrs['Street'] : getAttr('Street', seg);
	var emptyst = ((stname == null) || (stname == "")) ? true : false;
	var fattr = {cityID: newAttrs['cityID'], isEmpty: emptyst};
	if (emptyst == false) {
		fattr.name = stname;
	}
	var st = Waze.model.streets.getByAttributes(fattr);
	if (st.length === 1) {
		st = st[0];
	} else if (st.length === 0) {
		addons.log('Info : Creating new street object...');
		var a = new Waze.Action.CreateObject(Waze.Model.ObjectType.STREET, {
			name: stname,
			isEmpty: emptyst,
			cityID: newAttrs['cityID']
		});
		Waze.model.actionManager.add(a);
		st = a.newObject;
	} else {
		addons.log('Aborted : Multiple streets with same name on same city, please check');
		return false;
	}
	newAttrs.primaryStreetID = st.getID();
	return true;
}

function setAttrs(attrs, segs) {
	segs.forEach(function(seg) {
		var newAttrs = jQuery.extend(true, {}, attrs);
		if (
			(seg.isLockedByHigherRank() === false)
			&& (seg.type == Waze.Model.ObjectType.SEGMENT)
			&& (seg.isAllowed(seg.PERMISSIONS.EDIT_PROPERTIES))
			&& (setAddress(attrs, newAttrs, seg) === true)
			&& (getOrCreateStreet(newAttrs, seg) === true)
			) {
			delete newAttrs.StreetName;
			delete newAttrs.StreetId;
			delete newAttrs.Street;
			delete newAttrs.countryID;
			delete newAttrs.stateID;
			delete newAttrs.cityID;
			delete newAttrs.City;
			var action = new Waze.Action.UpdateSegmentDetails(seg, newAttrs);
			Waze.model.actionManager.add(action);
		}
	});
}

function mapObj(obj, f) {
	return Object.values(obj).map(f).filter(function(i) {
		return i;
	});
}

propertyDialog = Class.extend({
	init: function() {
		this.rows = ["City", "Street", "StreetId", "StreetName"];
		this.popup = $(createElement(document.body, 'DIV', 'PropertyDialog'))
			.css('font-size', '70.5%');
		this.plist = $('<div>');
		this.popup.dialog({
			autoOpen: false,
			show: "fast",
			width: 330,
			height: 258,
			dialogClass: "propedit",
			title: "Properties editor",
			buttons: {
				Cancel: function() {
					$(this).dialog("close");
				},
				Apply: function() {
					var attrs = {};
					$.each($('input', this).filter(':checked'), function(id, val) {
						attrs[val.name] = $('input[id=' + val.name + ']')[0].value;
					});
					setAttrs(attrs, Waze.selectionManager.selectedItems);
				}
			}
		});
		this.popup.append(this.plist);
		$('div.propedit')
			.attr('style', 'position: absolute; top: 0; left: 0; padding: .2em; width: 300px; overflow: hidden;background:rgba(255, 255, 255, ' + toSave.alpha / 100 + ')');
		$('div.ui-dialog-titlebar', $('div.propedit'))
			.attr('style', 'height:10px;font-size:8px;line-height: 10px')
			.append($('<span height="10px">')
			.button({icons: {primary: 'ui-icon-refresh'}})
			.attr('title', 'Refresh properties')
			.click(function(e) {
			refreshEdit();
		}));
		$('div.ui-dialog-buttonpane')
			.attr('style', 'height:25px;font-size:8px;line-height: 10px').last()
			.append($('<div>').slider({
			value: toSave.alpha,
			change: function(event, ui) {
				$('div.propedit')
					.css('background', 'rgba(255, 255, 255,' + ui.value / 100 + ')');
				toSave.alpha = ui.value;
			}
		}).attr('style', 'float:left;margin-top: 10px;width:50%'));
	},
	refresh: function() {
		var cols = ["Edit", "Attribute", "Value"];
		var available = [];
		available['Street'] = mapObj(Waze.model.streets.objects, _("name")).unique();
		available['City'] = mapObj(Waze.model.cities.objects, _("name")).unique();
		var rows = this.rows;
		this.plist.empty();
		var myTable = $('<table id="seg-list" border="1px solid #eee" margin="1em 0" padding=".6em 10px" border-collapse="collapse" width="100%" text-align="left">');
		var myHead = $('<thead>');
		var myRow = $('<tr class="ui-widget-header">');
		$.each(cols, function(index, value) {
			myRow.append('<td>' + value);
		});
		myHead.append(myRow);
		myBody = $('<tbody>');
		var attrs = {};
		Waze.selectionManager.selectedItems.forEach(function(seg) {
			if (seg.type == Waze.Model.ObjectType.SEGMENT) {
				$.each(rows, function(index, value) {
					var attr = getAttr(value, seg);
					attrs[value] = (value in attrs && attrs[value] != attr) ? "Multiple" : attr;
				});
			}
		});
		$.each(rows, function(index, value) {
			var tr = $('<tr>');
			var inp = $('<input id=' + value + ' value="' + attrs[value] + '" style="width:99%"></input>')
				.prop('disabled', true).autocomplete({source: available[value]});
			var chk = $('<input name="' + value + '" type="checkbox"></input>')
				.change(function() {
				$('#' + value).prop('disabled', !$(this).is(':checked'));
			});
			$('<td width="10px">').append(chk).appendTo(tr);
			tr.append('<td width="70px">' + value + '</td>');
			$('<td>').append(inp).appendTo(tr);
			myBody.append(tr);
		});
		myTable.append(myHead);
		myTable.append(myBody);
		this.plist.append(myTable);
	}
});

function refreshEdit() {
	dlgedt.refresh();
}

function PopupEdit() {
	if (typeof(dlgedt) === 'undefined') {
		dlgedt = new propertyDialog();
	}
	if (Waze.selectionManager.selectedItems.length == 0) {
		addons.log("No segment selected");
	} else {
		dlgedt.refresh();
		dlgedt.popup.dialog("open");
	}
}

function getUrlVars(href) {
	var vars = {}, hash;
	var idx = href.indexOf('?');
	var hashes = href.slice(idx + 1).split('&');
	vars[0] = href.slice(0, idx);
	for (var i = 0; i < hashes.length; i++) {
		hash = hashes[i].split('=');
		vars[hash[0]] = hash[1];
	}
	return vars;
}

function getCoord() {
	var mapLoc = localStorage.getItem("mapLocation");
	mapLoc = JSON.parse(mapLoc);
	var b = OpenLayers.Projection.transform({x: mapLoc.lon, y: mapLoc.lat},
	Waze.map.projection, Waze.map.displayProjection);
	mapLoc.lon = b.x;
	mapLoc.lat = b.y;
	return mapLoc;
}

function openLiveMap() {
	var zoom = Waze.map.getZoom();
	href = $(livemap)[0].href;
	if (zoom >= 4)
		zoom = 9;
	else if (zoom >= 2)
		zoom += 5;
	else
		zoom += 6;
	window.open(href + "&zoom=" + zoom);
}

function buildUrl(dic) {
	var href = [dic[0]];
	var first = true;
	for (var e in dic) {
		if (e != 0) {
			if (first) {
				href.push('?');
				first = false;
			}
			else
				href.push('&');
			href.push(e, '=', dic[e]);
		}
	}
	return href.join('');
}

function openIn(lnk) {
	var mapLoc = getCoord();
	var url = lnk.replace('%lat%', mapLoc.lat);
	url = url.replace('%lon%', mapLoc.lon);
	url = url.replace('%zoom%', mapLoc.zoom);
	var m = url.match(/(?:\()(\w+\+\w+)(?:\){1})/);
	if (m && m.length == 2) {
		res = m[1].split('+');
		if (res.length == 2) {
			val = parseInt(res[0]) + parseInt(res[1]);
			url = url.replace(m[0], val);
		}

	}
	window.open(url);
}

function storeLink(urlname, url) {
	toSave['customLinks'][urlname] = url;
	addons.log("Link saved, refresh the page to load your changes");
}

function suppressLink(urlname) {
	delete toSave['customLinks'][urlname];
	addons.log("Link deleted, refresh the page to load your changes");
}

linksDialog = Class.extend({
	init: function() {
		this.popup = $('<div>').appendTo($("body")).css('font-size', '70.5%');
		this.links = $('<div>');
		this.links.append('<div>Use %lat% for latitude %lon% for longitude and %zoom% for zoom level');
		this.links.append('<div>To add an offset value, put it in brackets with the + operator (eg: (12+%zoom%)');
		this.table = $('<table id="link-list" border="1px solid #eee" margin="1em 0" padding=".6em 10px" border-collapse="collapse" width="100%" text-align="left">');
		this.links.append(this.table);
		this.popup.dialog({
			autoOpen: false,
			show: "fast",
			width: 500,
			height: 258,
			dialogClass: "linksedit",
			title: "Configure links"
		});
		this.popup.append(this.links);
	},
	refresh: function() {
		this.table.empty();
	},
	addRow: function(lnkname, lnkstr) {
		var myRow = $('<tr>');
		var myInputName = $('<td style="width:100px"><input id=urlname value="' + lnkname + '" style="width:99%">')
			.appendTo(myRow);
		var myInputLink = $('<td><input id=url value="' + lnkstr + '" style="width:99%">')
			.appendTo(myRow);

		var btAdd = $('<td style="width:30px">')
			.append($('<button style="width:100%;height:100%" title="Save this entry">')
			.button({icons: {primary: 'ui-icon-disk'}, text: false})
			.click(function() {
			storeLink($(this).parent().parent().children()
				.find('#urlname')[0].value, $(this).parent().parent().children()
				.find('#url')[0].value);
		})).appendTo(myRow);

		var btDel = $('<td style="width:30px">')
			.append($('<button style="width:100%;height:100%" title="Delete this entry">')
			.button({icons: {primary: 'ui-icon-close'}, text: false})
			.click(function() {
			suppressLink($(this).parent().parent().children()
				.find('#urlname')[0].value);
		})).appendTo(myRow);

		var btTest = $('<td style="width:30px">')
			.append($('<button style="width:100%;height:100%" title="Test your link">')
			.button({icons: {primary: 'ui-icon-link'}, text: false})
			.click(function() {
			openIn($(this).parent().parent().children().find('#url')[0].value);
		})).appendTo(myRow);

		myRow.appendTo(this.table);
	}
});

function editLinks() {
	if (typeof(dlglinks) === 'undefined') {
		dlglinks = new linksDialog();
	}
	dlglinks.refresh();
	$.each(toSave['customLinks'], function(k, v) {
		dlglinks.addRow(k, v);
	});
	dlglinks.addRow("", "");
	dlglinks.popup.dialog("open");

//  dlglinks.addRow('Google Map','http://maps.google.com/maps?ll=%lat%,%lon%&z=(12+%zoom%)');
}

function initAddons() {
	addons = new wme_addons();
	addons.icon = document["WME_Icon"].src;
	var bt = addons.add_menu_bt("WME-Addons", document["WME_Icon"].src);
	addons.add_menu_entry(bt.menu, "Segment list", segmentList, "Show list of loaded segments on WazeMap with some filters");
	addons.add_menu_entry(bt.menu, "Properties", PopupEdit, "Edit properties of selected segments");
	var submenu = addons.add_submenu_entry(bt.menu, "Select in landmark >", "Select all segments inside the selected landmark");
	addons.add_submenu_item(submenu, "Large", CSelectLandMark, false, "Select all segments even partially in a landmark");
	addons.add_submenu_item(submenu, "Strict", CSelectLandMark, true, "Select all segments which are fully contained in a landmark");
	addons.add_menu_entry(bt.menu, "Clean Roundabout", cleanRDBT, "Set automatically many properties of all segments of a roundabout by selecting only one piece");
	var submenu = addons.add_submenu_entry(bt.menu, "Open in >", "Open same location on other maps");
	addons.add_submenu_item(submenu, "Edit links", editLinks);
	$.each(toSave['customLinks'], function(k, v) {
		addons.add_submenu_item(submenu, k, openIn, v);
	});
//	mz20130716: add other map link
	addons.add_submenu_item(submenu, "GMaps", openIn, "https://maps.google.it/?q=%lat%+%lon%&hl=it&hl=it&t=h&z=18");
	addons.add_submenu_item(submenu, "GMaps Beta", openIn, "https://www.google.com/maps/preview#!q=%lat%+%lon%");
	addons.add_submenu_item(submenu, "Bing", openIn, "http://it.bing.com/maps/?v=2&cp=%lat%~%lon%&lvl=18");
	addons.add_submenu_item(submenu, "ViaMichelin", openIn, "http://www.viamichelin.it/web/Mappe-Piantine/?strCoord=%lon%*%lat%&zoomLevel=15");
//
	addons.add_submenu_item(submenu, "Live Map", openLiveMap);
	addons.add_menu_entry(bt.menu, "Suppress extra junctions", CSuppressUnneededJunctions, "Suppress nodes which doesn't seem to be necessary on the whole current map");

	var mySpinner = addons.add_menu_entry(bt.menu, "", null);
	var tolerance = toSave.snapdst;
	var toleranceField;

	mySpinner.append($("<span style='text-align:left'>").append("Snap dist: "))
		.append($("<button style='width:20px;display:inline-block'>").append("<")
		.click(function(e) {
		if (tolerance > 0)
			toleranceField.text(tolerance -= 5);
		toSave.snapdst = tolerance;
	}))
		.append(toleranceField = $("<span style='width:3em;display:inline-block;'>")
		.append(tolerance))
		.append($("<button style='width:20px;display:inline-block;'>").append(">")
		.click(function(e) {
		toleranceField.text(tolerance += 5);
		toSave.snapdst = tolerance;
	}));

	addons.add_menu_entry(bt.menu, "About", About, "Display the current release of WME Addons");

	var user = Waze.loginManager.user;
	if (user !== null) {
		addons.log("Hello " + user.userName + " (" + user.normalizedLevel + ")");
	} else {
		addons.log("Hello Stranger");
	}

	var testTargetOrig = Waze.Control.Snapping.prototype.testTarget;
	Waze.Control.Snapping.prototype.testTarget = function(tol, target) {
		var l = ["edgeTolerance", "nodeTolerance", "tolerance", "vertexTolerance"];
		for (var f in l)
			tol[l[f]] = tolerance;
		return testTargetOrig.call(this, tol, target);
	};

	Waze.model.cameras.minZoom = 0;
	var widthtomove = ($("#sidebar").width() * 100) / document.body.clientWidth;
	var sideoffset = (parseInt($("#sidebar").parent().parent()
		.css('padding-left')) * 100) / document.body.clientWidth;
	$('#sidebar')
		.prepend('<div id="slider" title="Hide the side bar" style="float:right;background:rgba(0, 0, 0, 0.6);font-size: 100%;color:white;cursor: pointer;"><');
	$("#editor-container").css("position", "absolute");
	$("#editor-container").css("width", (100 - widthtomove - sideoffset) + "%");
	$('#slider').click(function() {
		slide();
	});
}

window.onresize = function(event) {
	var widthtomove = ($("#sidebar").width() * 100) / document.body.clientWidth;
	var sideoffset = (parseInt($("#sidebar").parent().parent()
		.css('padding-left')) * 100) / document.body.clientWidth;
	if ($("#sidebar").position().left > 0) {
//	  $("#editor-container").attr('style', function(i,s) { return s + 'max-width:'+(document.body.clientWidth-parseInt($("#sidebar").parent().parent().css('padding-left')))+'px;width:100%;' });
	} else {
//	  $("#editor-container").attr('style', function(i,s) { return s + 'max-width:'+(document.body.clientWidth-$("#sidebar").width()-parseInt($("#sidebar").parent().parent().css('padding-left')))+'px;width:100%;' });
	}
//  $("#editor-container").attr('style', function(i,s) { return s + 'max-width:'+(document.body.clientWidth-$("#sidebar").width()-parseInt($("#sidebar").parent().parent().css('padding-left')))+'px;' });
//  $("#editor-container").attr('style', function(i,s) { return s + 'max-width:6000px ;' });
//  addons.tb.width=parseInt(addons.tb.css("width"))+(parseInt(addons.tb.css("width"))/6);
//  addons.tb.css("width", addons.tb.width+"px");
};

function slide() {
	var widthtomove = ($("#sidebar").width() * 100) / document.body.clientWidth;
	var sideoffset = (parseInt($("#sidebar").parent().parent()
		.css('padding-left')) * 100) / document.body.clientWidth;
	if ($("#sidebar").position().left > 0) {
		$("#sidebar").animate({"left": "-=" + (widthtomove) + "%"}, 100, function() {
			$("#editor-container")
				.css({left: +sideoffset + '%', width: (100 - sideoffset) + '%'});
		});
		$('#slider').text('>');
	} else {
		$("#sidebar").animate({"left": "+=" + (widthtomove) + "%"}, 100, function() {
			$("#editor-container")
				.css({left: (sideoffset + widthtomove) + '%', width: (100 - widthtomove - sideoffset) + '%'});
		});
		$('#slider').text('<');
	}
}
;

// Check if jQuery's loaded
function wait_addons() {
	if ((typeof jQuery.ui == 'undefined') || (typeof Waze.loginManager == 'undefined')) {
		window.setTimeout(wait_addons, 100);
	} else {
		initAddons();
		addons.log("WME Add-Ons V" + version + " loaded");
	}
}
;

function About() {
	$("<div align='center'>").attr("title", "About")
		.append("<div>WME-Addons version: " + version)
		.append("<div> Copyright (c) 2012 - 2013 Gilles Dupeyrou ")
		.append("<div> v0.45 modified by zanna+waze@gmail.com  ")
		.append("<div>Based on WME-Extended tools script")
		.append("<div>(https://waze-papyrus-extended-tools.googlecode.com)")
		.append("<div>Licensed under the MIT license")
		.append("<div> (http://www.opensource.org/licenses/mit-license.php).")
		.css('font-size', '60.5%')
		.dialog({width: 350, resizable: false});
}
;

// Add jQuery
var JQ = document.createElement('script');
JQ.type = 'text/javascript';
JQ.src = "//ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/jquery-ui.min.js";
JQ.onload = function() {
};

var ST_JQ = document.createElement('link');
ST_JQ.type = 'text/css';
ST_JQ.rel = 'stylesheet';
ST_JQ.href = "//ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/themes/base/jquery-ui.css";
ST_JQ.onload = function() {
};

document.body.appendChild(JQ);
document.head.appendChild(ST_JQ);
wait_addons();
